// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/parser/parser.h>
#include <cantor/parser/grammar/scanner.h>
#include <turbo/times/time.h>

extern int sql_parse(yyscan_t scanner, cantor::parser::SqlParser *parser);

namespace cantor::parser {
    void SqlParser::change_5c_to_7f(std::string &sql) {
        size_t i = 0;
        while (i < sql.size()) {
            if ((sql[i] & 0x80) != 0) {
                if (++i >= sql.size()) {
                    return;
                }
                if (sql[i] == 0x5C) {
                    sql[i] = 0x7F; // gbk second byte can not be 0x7F
                    has_5c = true;
                }
            }
            ++i;
        }
    }

    struct SqlParserImpl {
        SqlParserImpl() = default;
        ~SqlParserImpl() = default;
        yyscan_t scanner;
        YY_BUFFER_STATE bp;
    };

    void SqlParser::parse(const std::string &sql_) {
        KCHECK(impl_ == nullptr)<<"already parsed";
        turbo::TimeCost time_cost;
        std::string sql = sql_;
        impl_ = new SqlParserImpl;
        if (charset ==Charset::CHARSET_GBK) {
            is_gbk = true;
        } else {
            is_gbk = false;
        }
        if (is_gbk) {
            change_5c_to_7f(sql);
        }

        sql_lex_init(&impl_->scanner);

        impl_->bp = sql__scan_bytes(sql.c_str(), sql.size(), impl_->scanner);
        impl_->bp->yy_bs_lineno = 1;
        impl_->bp->yy_bs_column = 0;
        _buffer_input = impl_->bp->yy_ch_buf;
        sql__switch_to_buffer(impl_->bp, impl_->scanner);
        sql_parse(impl_->scanner, this);
        parse_cost_nano = time_cost.n_elapsed();
    }
    SqlParser::~SqlParser() {
        if (impl_) {
            sql__delete_buffer(impl_->bp, impl_->scanner);
            sql_lex_destroy(impl_->scanner);
            delete impl_;
            impl_ = nullptr;
        }
    }
}  // namespace cantor::parser
